package hyl.core.conf;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Serializable;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import hyl.core.MyCharset;
import hyl.core.MyFun;
import hyl.core.io.MyFile;
import hyl.core.io.MyPath;
import hyl.core.reflect.MySerial;

/**
 * 
 * @className: MyConfig
 * 
 *             <p>
 *             Description: 默认处理5种配置，其它配置可以调用函数自行读取 5种配置分别是
 *             redis，数据库，本地缓存，语言环境，系统变量
 *             </p>
 *             <p>
 *             本身还可以解析各种配置文件 主要是 json ini sql 存储过程 txt
 *             </p>
 * @author: zoudyaou qq:37798955
 * @date: 2018年11月13日 下午4:18:14
 * @copyright: 2018 zoudayou Inc. All rights reserved.
 *             注意：代码版权归邹达有所有，任何人未经授权不得私自用于商业目的
 */
public class MyConfig implements Serializable {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	static Logger logger = LoggerFactory.getLogger(MyConfig.class);
	protected static final String CONFIG_ROOT = "config.json";
	// 数据库配置
	private Map<String, JSONObject> CONFIGS_DB = null;
	// redis配置
	private Map<String, Map<String, String>> CONFIGS_REDIS = null;
	// 缓存配置
	private Map<String, Map<String, String>> CONFIGS_CACHE = null;
//mail 配置
	private Map<String, Map<String, String>> CONFIGS_MAIL = null;
	// sms配置
	private Map<String, Map<String, String>> CONFIGS_SMS = null;
	// hbase配置
	private Map<String, Map<String, String>> CONFIGS_HBASE = null;
	private Map<String, Object> CONFIGS_KV = null;

	// 更新日志
	public String UPDATEFILE = null;
	// 语言配置
	private String CONFIGS_LANG = null;
	// 环境变量
	private String CONFIGS_CONST = null;

//	public static final String UTF8 = "utf-8";//已经有个MyCharset.utf8 了 这个就不能再用了,必须尽快统一起来
	protected boolean enable = false;
//	private static final String ERRNOFILE = "配置文件不存在";
	public static MyConfig _config = null;

	static {
		ini();
	}

	/**
	 * 载入核心配置文件的配置 ，包含其他配置文件的路径 CONFIGS_MAIL
	 * 
	 * @throws IOException
	 */
	public static MyConfig ini() {

		// MyPath.test(MyConfig.class);
		if (_config != null)
			return _config;
		// MyPath.test(MyConfig.class);
		// 配置优先从配置序列化文件读取,如果要改动需要删除序列化配置文件
		// 优点是不用来回改配置,加载速度也会更快
		String path = MyPath.getLastPathOfClassLoader(MyConfig.class.getClassLoader());
		if (MyFun.isEmpty(path)) {
			path = MyPath.getPathOfPro();
		}
		String hyl序列化文件 = path + "hyl_conf.serial";
		System.out.println("序列化配置目录:" + path);
		File confclassfile = MyFile.openFile(hyl序列化文件);
		// logger.info("序列化配置文件:" + hyl序列化文件);
		long l = confclassfile.length();
		if (confclassfile != null && l > 0) {
			_config = MySerial.deserialize(confclassfile);
			return _config;
		}

		_config = new MyConfig();
		InputStream inputStream;
		try {
			// inputStream = MyPath.getInputStreamFromClassLoadFile(CONFIG_ROOT);
			inputStream = MyFile.findInputstream(CONFIG_ROOT);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}

		String text = MyFile.readAllByString(inputStream, null);
		System.out.println("配置:" + text);
		// SuppressWarnings("unchecked")
		JSONObject pps = JSONObject.parseObject(text);
		if (pps == null)
			return null;
		// 取本地化配置
		String file = pps.getString("lang");
		if (!MyFun.isEmpty(file))
			_config.CONFIGS_LANG = file;

		// 读取环境变量配置
		file = pps.getString("const");
		if (!MyFun.isEmpty(file))
			_config.CONFIGS_CONST = file;

		// 读取数据库配置
		file = pps.getString("db");
		if (!MyFun.isEmpty(file))
			_config.CONFIGS_DB = loadJson(file, MyCharset._UTF8);
		// System.out.println("db="+JSON.toJSON(_config.CONFIGS_DB));
		// 读取redis配置
		file = pps.getString("redis");
		if (!MyFun.isEmpty(file))
			_config.CONFIGS_REDIS = loadJson(file, MyCharset._UTF8);
		// 读取cache配置
		file = pps.getString("cache");
		if (!MyFun.isEmpty(file))
			_config.CONFIGS_CACHE = loadJson(file, MyCharset._UTF8);
		// 读取mail配置
		file = pps.getString("mail");
		if (!MyFun.isEmpty(file))
			_config.CONFIGS_MAIL = loadJson(file, MyCharset._UTF8);
		// 读取sms配置
		file = pps.getString("sms");
		if (!MyFun.isEmpty(file))
			_config.CONFIGS_SMS = loadJson(file, MyCharset._UTF8);
		file = pps.getString("hbase");
		if (!MyFun.isEmpty(file))
			_config.CONFIGS_HBASE = loadJson(file, MyCharset._UTF8);

		file = pps.getString("kv");
		if (!MyFun.isEmpty(file))
			_config.CONFIGS_KV = loadJson(file, MyCharset._UTF8);

		// 读取更新日志
		_config.UPDATEFILE = pps.getString("update");
		// 读取成功
		_config.enable = true;

		MySerial.serialize(_config, confclassfile);

		return _config;
	}

	public static Map<String, JSONObject> getConfOfDb() {
		return _config.CONFIGS_DB;
	}

	public static Map<String, Map<String, String>> getConfOfRedis() {
		return _config.CONFIGS_REDIS;
	}

	public static Map<String, Map<String, String>> getConfOfSms() {
		return _config.CONFIGS_SMS;
	}

	public static Map<String, Map<String, String>> getConfOfCache() {
		return _config.CONFIGS_CACHE;
	}

	public static Map<String, Map<String, String>> getConfOfHbase() {
		return _config.CONFIGS_HBASE;
	}

	public static Map<String, Object> getConfOfKv() {
		return _config.CONFIGS_KV;
	}

	/**
	 * 多语言配置
	 * 
	 * @return
	 */
	public static String getConfOfLang() {
		return _config.CONFIGS_LANG;
	}

	public static Map<String, Map<String, String>> getConfOfMail() {
		return _config.CONFIGS_MAIL;
	}

	public static String getConfOfConst() {
		return _config.CONFIGS_CONST;
	}

	/**
	 * 解析 批量json 格式文件 注意文件不能为bom开头的utf-8 如果是请转成无bom 的utf-8
	 */
	@SuppressWarnings("unchecked")
	public static <T> T loadJson(String filename, Charset encode) {
		InputStream inputStream = MyFile.findInputstream(filename);
		return (T) readjson(inputStream, encode);
	}

	public static JSONObject loadJsonObj(String file, Charset encode) {
		InputStream isr = MyFile.findInputstream(file);
		return readjsonObj(isr, encode);
	}

	public static JSONArray loadJsonArr(String file, Charset encode) {
		InputStream isr = MyFile.findInputstream(file);
		return readjsonArr(isr, encode);
	}

	/**
	 * 解析 批量json 格式文件 注意文件不能为bom开头的utf-8 如果是请转成无bom 的utf-8
	 */
	@SuppressWarnings("unchecked")
	public static <T> T loadJson(File file, Charset encode) {
		InputStream isr = MyFile.getInputstream(file);
		return (T) readjson(isr, encode);
	}

	public static JSONObject loadJsonObj(File file, Charset encode) {
		InputStream isr = MyFile.getInputstream(file);
		return readjsonObj(isr, encode);
	}

	public static JSONArray loadJsonArr(File file, Charset encode) {
		InputStream isr = MyFile.getInputstream(file);
		return readjsonArr(isr, encode);
	}

	/**
	 * 解析 批量json 格式文件 注意文件不能为bom开头的utf-8 如果是请转成无bom 的utf-8
	 */
	public static Object readjson(InputStream inputStream, Charset filecode) {
		String text = MyFile.readAllByString(inputStream, filecode);
		Object pps1 = JSON.parse(text);
		return pps1;
	}

	public static JSONObject readjsonObj(InputStream inputStream, Charset filecode) {
		String text = MyFile.readAllByString(inputStream, filecode);
		return JSON.parseObject(text);
	}

	public static JSONArray readjsonArr(InputStream inputStream, Charset filecode) {
		String text = MyFile.readAllByString(inputStream, filecode);

		return JSON.parseArray(text);
	}

	public static boolean writeJson(File file, JSON obj) {
		return MyFile.writeBytes(file, JSON.toJSONString(obj).getBytes());
	}

	/**
	 * 所有属性名称自动转大写 微软会悄悄地在UTF-8编码的文件前面添加BOM头，<br>
	 * 所谓BOM头是在文件最开头的16进制的0xEF 0xBB 0xBF这三位。<br>
	 * 如果UTF-8编码的文件没有BOM头的话，Windows下的软件就可能无法识别UTF-8格式，<br>
	 * 采用其他的读取办法，从而就造成了乱码。Excel就是其中一个<br>
	 * 解析 批量ini 格式文件 注意文件不能为bom开头的utf-8 如果是请转成无bom 的utf-8
	 */
	public static void loadIni(String path, Charset encode, Map<String, String> pp) {

		InputStreamReader isr = MyFile.findInputstreamRead(path, encode);
		readMapFromIni(isr, pp);
	}

	/**
	 * 注意:所有属性名称自动转大写
	 * 
	 * @param path
	 * @param encode
	 * @return
	 * @throws IOException
	 */
	public static Map<String, String> loadIni(String path, Charset encode) {
		try {
			InputStreamReader isr = MyFile.findInputstreamRead(path, encode);
			return readMapFromIni(isr);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 注意:所有属性名称自动转大写<br>
	 * 解析 批量ini 格式文件 注意文件不能为bom开头的utf-8 如果是请转成无bom 的utf-8
	 */
	public static void loadIni(File file, Charset encode, Map<String, String> pp) {
		InputStreamReader isr = MyFile.getInputstreamRead(file, encode);
		readMapFromIni(isr, pp);
	}

	/**
	 * 所有属性名称自动转大写
	 * 
	 * @param file
	 * @param encode
	 * @return
	 * @throws IOException
	 */
	public static Map<String, String> loadIni(File file, Charset encode) {
		try {
			InputStreamReader isr = MyFile.getInputstreamRead(file, encode);
			return readMapFromIni(isr);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 所有属性名称自动转大写,<br>
	 * 注意文件不能为bom开头的utf-8 如果是请转成无bom 的utf-8
	 */
	public static void loadIni(String[] list, Charset encode, Map<String, String> pp) {
		if (list == null || list.length == 0) {
			return;
		}
		for (String filename : list) {
			InputStreamReader isr = MyFile.findInputstreamRead(filename, encode);
			readMapFromIni(isr, pp);
		}
	}

	public static Map<String, String> readMapFromIni(InputStreamReader isr) {
		HashMap<String, String> pp = new HashMap<>();
		readMapFromIni(isr, pp);
		return pp;
	}

	/**
	 * 解析 批量ini 格式文件
	 */
	// 注意文件不能为bom开头的utf-8
	public static void readMapFromIni(InputStreamReader isr, Map<String, String> pp) {
		if (isr == null)
			return;
		BufferedReader br = new BufferedReader(isr, 128 * 1024);
		String line;
		// 读取第一行
		try {
			while ((line = br.readLine()) != null) { // 如果 line 为空说明读完了
				int f = 0;// 0 key 开始，1key 进行 2value 开始 3value 进行 9异常
				StringBuilder key = new StringBuilder();
				StringBuilder value = new StringBuilder();
				for (int i = 0; i < line.length(); i++) {
					char c = line.charAt(i);
					if (c == '#') {
						if (f < 3) {// 没有value 出现等号为错误
							f = 9;
							break;
						}
						if (f == 3)
							break;

					}
					if (c == '=') {
						if (f == 1) {
							f = 2;
							continue;
						} else if (f == 0) { // 没有key 出现等号为错误
							f = 9;
							break;
						}
					}
					if (f < 2) {// 添加field
						if (c == ' ')
							continue;
						key.append(line.charAt(i));
						f = 1;
					} else if (f < 4) {// 添加value
						value.append(line.charAt(i));
						f = 3;
					}
				}
				if (f == 3)
					pp.put(key.toString().toUpperCase(), value.toString().trim());
			}
		} catch (IOException e) {

			e.printStackTrace();
		}
	}

	/**
	 * 解析 批量sql文件
	 */
	public static void loadSql(String path, Charset encode, List<String> pp) throws IOException {
		InputStreamReader isr = MyFile.findInputstreamRead(path, encode);
		readFromSql(isr, pp);
	}

	/**
	 * 解析 存储过程文件
	 */
	public static void loadProd(File file, Charset encode, List<String> pp) throws IOException {
		InputStreamReader isr = MyFile.getInputstreamRead(file, encode);
		readFromSql(isr, pp);
	}

	/**
	 * 解析 存储过程文件
	 */
	public static void loadProd(String path, Charset encode, List<String> pp) {
		InputStreamReader isr = MyFile.findInputstreamRead(path, encode);
		readFromProd(isr, pp);
	}

	public static void loadSql(File file, Charset encode, List<String> pp) {
		InputStreamReader isr = MyFile.getInputstreamRead(file, encode);
		readFromProd(isr, pp);
	}

	/**
	 * 解析 sql文件
	 */
	// 注意文件不能为bom开头的utf-8
	public static void readFromSql(InputStreamReader isr, List<String> sqls) {
		BufferedReader br = new BufferedReader(isr, 128 * 1024);
		String line;
		int f = 0;// 行标记
		// char cl = 1;
		StringBuilder sql = new StringBuilder();
		// 读取第一行
		try {
			while ((line = br.readLine()) != null) {
				f = 0;
				for (int i = 0; i < line.length(); i++) {
					char c = line.charAt(i);
					if (f == 0) {
						if (c == ' ')
							continue;
						if (c == '#' || c == '-' || c == '/') {
							break; // 终止后续内容
						}
					}
					if (c == ';') {
						sqls.add(sql.toString());
						sql = new StringBuilder();
						continue;
					}
					if (f < 3) {// 添加field
						f = 1; // 有内容了
						sql.append(c);
					}
				}
				sql.append("\r\n");
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * 解析 存储过程文件
	 */
	// 注意文件不能为bom开头的utf-8
	public static void readFromProd(InputStreamReader isr, List<String> sqls) {
		BufferedReader br = new BufferedReader(isr, 128 * 1024);
		String line;
		int f = 0;// 行标记
		char cl = 1;
		StringBuilder sql = new StringBuilder();
		// 读取第一行
		try {
			while ((line = br.readLine()) != null) {
				f = 0;
				for (int i = 0; i < line.length(); i++) {
					char c = line.charAt(i);
					if (c == '$') {
						if (cl == '$') {
							sqls.add(sql.toString());
							sql = new StringBuilder();
							cl = 1;
						}
						cl = '$';
						continue;
					}
					if (f < 3) {// 添加field
						f = 1; // 有内容了
						sql.append(c);
					}
				}
				sql.append("\r\n");
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public static String loadTxt(String path) {
		return loadTxt(path, MyCharset._UTF8);
	}

	public static String loadTxt(String path, Charset encode) {
		InputStream isr = MyFile.findInputstream(path);
		return readFromTxt(isr, encode);
	}

	/**
	 * 读取文本文件 注意文件不能为bom开头的utf-8 如果是请转成无bom 的utf-8
	 */
	public static String loadTxt(File file, Charset encode) {
		InputStream isr = MyFile.getInputstream(file);
		return readFromTxt(isr, encode);
	}

	/**
	 * 读取文本文件 注意文件不能为bom开头的utf-8 如果是请转成无bom 的utf-8
	 */
	public static String readFromTxt(InputStream isr, Charset encode) {
		return MyFile.readAllByChars(isr, encode);
	}

	/**
	 * 读取属性文件 注意文件不能为bom开头的utf-8 如果是请转成无bom 的utf-8
	 */
	public static Properties getProperties(String filename) {
		InputStream is = MyFile.findInputstream(filename);
		return getProperties(is);
	}

	/**
	 * 读取属性文件 注意文件不能为bom开头的utf-8 如果是请转成无bom 的utf-8
	 */
	public static Properties getProperties(InputStream is) {
		if (is == null) {
			return null;
		}
		Properties properties = new Properties();
		try {
			properties.load(is);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
		return properties;
	}

	public Map<String, JSONObject> getCONFIGS_DB() {
		return CONFIGS_DB;
	}

	public void setCONFIGS_DB(Map<String, JSONObject> cONFIGS_DB) {
		CONFIGS_DB = cONFIGS_DB;
	}

	public Map<String, Map<String, String>> getCONFIGS_REDIS() {
		return CONFIGS_REDIS;
	}

	public void setCONFIGS_REDIS(Map<String, Map<String, String>> cONFIGS_REDIS) {
		CONFIGS_REDIS = cONFIGS_REDIS;
	}

	public Map<String, Map<String, String>> getCONFIGS_CACHE() {
		return CONFIGS_CACHE;
	}

	public void setCONFIGS_CACHE(Map<String, Map<String, String>> cONFIGS_CACHE) {
		CONFIGS_CACHE = cONFIGS_CACHE;
	}

	public String getUPDATEFILE() {
		return UPDATEFILE;
	}

	public void setUPDATEFILE(String uPDATEFILE) {
		UPDATEFILE = uPDATEFILE;
	}

	public String getCONFIGS_LANG() {
		return CONFIGS_LANG;
	}

	public void setCONFIGS_LANG(String cONFIGS_LANG) {
		CONFIGS_LANG = cONFIGS_LANG;
	}

	public String getCONFIGS_CONST() {
		return CONFIGS_CONST;
	}

	public void setCONFIGS_CONST(String cONFIGS_CONST) {
		CONFIGS_CONST = cONFIGS_CONST;
	}

	public Map<String, Map<String, String>> getCONFIGS_MAIL() {
		return CONFIGS_MAIL;
	}

	public void setCONFIGS_MAIL(Map<String, Map<String, String>> cONFIGS_MAIL) {
		CONFIGS_MAIL = cONFIGS_MAIL;
	}

	public Map<String, Map<String, String>> getCONFIGS_SMS() {
		return CONFIGS_SMS;
	}

	public void setCONFIGS_SMS(Map<String, Map<String, String>> cONFIGS_SMS) {
		CONFIGS_SMS = cONFIGS_SMS;
	}

	public Map<String, Object> getCONFIGS_KV() {
		return CONFIGS_KV;
	}

	public void setCONFIGS_KV(Map<String, Object> cONFIGS_KV) {
		CONFIGS_KV = cONFIGS_KV;
	}

//有 get set方法的可以序列化，不想序列化就不写 
	public boolean isEnable() {
		return enable;
	}

	public void setEnable(boolean enable) {
		this.enable = enable;
	}

}
